home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / syslog / syslogd.c < prev   
C/C++ Source or Header  |  1992-08-22  |  31KB  |  1,389 lines

  1. /*  $Revision: 1.9 $
  2. **  This file has been modified to get it to compile more easily
  3. **  on pre-4.4BSD (e.g., SysVr4 :-) systems.  Rich $alz, June 1991.
  4. */
  5.  
  6.     /* change these three if you must keep running an old syslog. */
  7. #define    _PATH_LOGFILE    "/dev/log"
  8. #define    _PATH_LOGCONF    "/etc/syslog.conf"
  9. #define    _PATH_LOGPID    "/etc/syslog.pid"
  10.  
  11.     /* #define this to enable verbose debugging of all messages. */
  12. #undef VERBOSE_DEBUG
  13.     /* #define this to line to listen on the INET port. */
  14. #undef DO_INET_SOCKET
  15.     /* #undef this to not read kernel syslog messages. */
  16. #define    _PATH_KLOG    "/dev/klog"
  17. #undef _PATH_KLOG
  18.     /* set this depending on what your sighandler is. */
  19.     /* =()<#define SIGHANDLER    @<SIGHANDLER>@>()= */
  20. #define SIGHANDLER    void
  21.     /* if you need various BSD functions, set  this. */
  22. #define NEED_BZERO_ETC
  23.  
  24.     /* Use "union wait" instead of int? */
  25.     /* =()<#define @<USE_UNION_WAIT>@_USE_UNION_WAIT>()= */
  26. #define DO_USE_UNION_WAIT
  27. #if    defined(DO_USE_UNION_WAIT)
  28. #define WAITVALUE    union wait
  29. #else
  30. #define WAITVALUE    int
  31. #endif    /* defined(DO_USE_UNION_WAIT) */
  32.  
  33. /*
  34.  * Copyright (c) 1983, 1988 Regents of the University of California.
  35.  * All rights reserved.
  36.  *
  37.  * Redistribution and use in source and binary forms are permitted provided
  38.  * that: (1) source distributions retain this entire copyright notice and
  39.  * comment, and (2) distributions including binaries display the following
  40.  * acknowledgement:  ``This product includes software developed by the
  41.  * University of California, Berkeley and its contributors'' in the
  42.  * documentation or other materials provided with the distribution and in
  43.  * all advertising materials mentioning features or use of this software.
  44.  * Neither the name of the University nor the names of its contributors may
  45.  * be used to endorse or promote products derived from this software without
  46.  * specific prior written permission.
  47.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  48.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  49.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  50.  */
  51.  
  52. #ifndef lint
  53. char copyright[] =
  54. "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
  55.  All rights reserved.\n";
  56. #endif /* not lint */
  57.  
  58. #ifndef lint
  59. static char sccsid[] = "@(#)syslogd.c    5.42 (Berkeley) 6/29/90";
  60. #endif /* not lint */
  61.  
  62. /*
  63.  *  syslogd -- log system messages
  64.  *
  65.  * This program implements a system log. It takes a series of lines.
  66.  * Each line may have a priority, signified as "<n>" as
  67.  * the first characters of the line.  If this is
  68.  * not present, a default priority is used.
  69.  *
  70.  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
  71.  * cause it to reread its configuration file.
  72.  *
  73.  * Defined Constants:
  74.  *
  75.  * MAXLINE -- the maximimum line length that can be handled.
  76.  * DEFUPRI -- the default priority for user messages
  77.  * DEFSPRI -- the default priority for kernel messages
  78.  *
  79.  * Author: Eric Allman
  80.  * extensive changes by Ralph Campbell
  81.  * more extensive changes by Eric Allman (again)
  82.  */
  83.  
  84. #define    MAXLINE        1024        /* maximum line length */
  85. #define    MAXSVLINE    120        /* maximum saved line length */
  86. #define DEFUPRI        (LOG_USER|LOG_NOTICE)
  87. #define DEFSPRI        (LOG_KERN|LOG_CRIT)
  88. #define TIMERINTVL    30        /* interval for checking flush, mark */
  89.  
  90. #include <sys/param.h>
  91. #include <sys/errno.h>
  92. #include <sys/ioctl.h>
  93. #include <sys/stat.h>
  94. #include <sys/wait.h>
  95. #include <sys/socket.h>
  96. #include <sys/file.h>
  97. #include <sys/uio.h>
  98. #include <sys/un.h>
  99. #include <sys/time.h>
  100. #include <sys/resource.h>
  101. #include <sys/signal.h>
  102.  
  103. #ifdef    MSG_BSIZE
  104. #undef    MSG_BSIZE
  105. #endif
  106. #define MSG_BSIZE    4096
  107.  
  108. #include <netinet/in.h>
  109. #include <netdb.h>
  110.  
  111. #include <utmp.h>
  112. #include <stdio.h>
  113. #include <ctype.h>
  114. #include <string.h>
  115.  
  116. #define SYSLOG_NAMES
  117. #include "syslog.h"
  118.  
  119. #define UT_NAMESIZE    8
  120. #define    _PATH_UTMP    "/etc/utmp"
  121. #define    _PATH_DEV    "/dev/"
  122. #define    _PATH_CONSOLE    "/dev/console"
  123.  
  124. #ifndef sigmask
  125. #define sigmask(m)      (1 << ((m)-1))
  126. #endif
  127. char    *LogName = _PATH_LOGFILE;
  128. char    *ConfFile = _PATH_LOGCONF;
  129. char    *PidFile = _PATH_LOGPID;
  130. char    ctty[] = _PATH_CONSOLE;
  131.  
  132. #define FDMASK(fd)    (1 << (fd))
  133.  
  134. #define    dprintf        if (Debug) printf
  135.  
  136. #define MAXUNAMES    20    /* maximum number of user names */
  137.  
  138. #ifdef NEED_BZERO_ETC
  139. #include <fcntl.h>
  140. bzero(b, length)
  141.     char *b;
  142.     int length;
  143. {
  144.     while (--length >= 0)
  145.     *b++ = '\0';
  146. }
  147. bcopy(b1, b2, length)
  148.     char *b1;
  149.     char *b2;
  150.     int length;
  151. {
  152.     while (--length >= 0)
  153.     *b2++ = *b1++;
  154. }
  155. setlinebuf(f)
  156.     FILE *f;
  157. {
  158.     setbuf(f, (char *)NULL);
  159. }
  160. wait3(status, flags, np)
  161.     WAITVALUE *status;
  162.     int flags;
  163.     struct rusage *np;
  164. {
  165.     return waitpid(-1, status, WNOHANG);
  166. }
  167.  
  168. /* Not a general mask handler -- it know what we call, below. */
  169. SIGHANDLER (*oldhup)(), (*oldalrm)();
  170. int
  171. sigsetmask(omask)
  172.     int omask;
  173. {
  174.     if (omask & sigmask(SIGHUP))
  175.     (void) signal(SIGHUP, oldhup);
  176.     if (omask & sigmask(SIGALRM))
  177.     (void) signal(SIGALRM, oldalrm);
  178. }
  179. int
  180. sigblock(mask)
  181.     int mask;
  182. {
  183.     if (mask & sigmask(SIGHUP))
  184.     oldhup = signal(SIGHUP, SIG_IGN);
  185.     if (mask & sigmask(SIGALRM))
  186.     oldhup = signal(SIGALRM, SIG_IGN);
  187. }
  188. #endif
  189.  
  190. /*
  191.  * Flags to logmsg().
  192.  */
  193.  
  194. #define IGN_CONS    0x001    /* don't print on console */
  195. #define SYNC_FILE    0x002    /* do fsync on file after printing */
  196. #define ADDDATE        0x004    /* add a date to the message */
  197. #define MARK        0x008    /* this message is a mark */
  198.  
  199. /*
  200.  * This structure represents the files that will have log
  201.  * copies printed.
  202.  */
  203.  
  204. struct filed {
  205.     struct    filed *f_nextone;    /* next in linked list */
  206.     short    f_type;            /* entry type, see below */
  207.     short    f_file;            /* file descriptor */
  208.     time_t    f_time;            /* time this was last written */
  209.     u_char    f_pmask[LOG_NFACILITIES+1];    /* priority mask */
  210.     union {
  211.         char    f_uname[MAXUNAMES][UT_NAMESIZE+1];
  212.         struct {
  213.             char    f_hname[MAXHOSTNAMELEN+1];
  214.             struct sockaddr_in    f_addr;
  215.         } f_forw;        /* forwarding address */
  216.         char    f_fname[MAXPATHLEN];
  217.     } f_un;
  218.     char    f_prevline[MAXSVLINE];        /* last message logged */
  219.     char    f_lasttime[16];            /* time of last occurrence */
  220.     char    f_prevhost[MAXHOSTNAMELEN+1];    /* host from which recd. */
  221.     int    f_prevpri;            /* pri of f_prevline */
  222.     int    f_prevlen;            /* length of f_prevline */
  223.     int    f_prevcount;            /* repetition cnt of prevline */
  224.     int    f_repeatcount;            /* number of "repeated" msgs */
  225. };
  226.  
  227. /*
  228.  * Intervals at which we flush out "message repeated" messages,
  229.  * in seconds after previous message is logged.  After each flush,
  230.  * we move to the next interval until we reach the largest.
  231.  */
  232. int    repeatinterval[] = { 30, 120, 600 };    /* # of secs before flush */
  233. #define    MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)
  234. #define    REPEATTIME(f)    ((f)->f_time + repeatinterval[(f)->f_repeatcount])
  235. #define    BACKOFF(f)    { if (++(f)->f_repeatcount > MAXREPEAT) \
  236.                  (f)->f_repeatcount = MAXREPEAT; \
  237.             }
  238.  
  239. /* values for f_type */
  240. #define F_UNUSED    0        /* unused entry */
  241. #define F_FILE        1        /* regular file */
  242. #define F_TTY        2        /* terminal */
  243. #define F_CONSOLE    3        /* console terminal */
  244. #define F_FORW        4        /* remote machine */
  245. #define F_USERS        5        /* list of users */
  246. #define F_WALL        6        /* everyone logged on */
  247.  
  248. char    *TypeNames[7] = {
  249.     "UNUSED",    "FILE",        "TTY",        "CONSOLE",
  250.     "FORW",        "USERS",    "WALL"
  251. };
  252.  
  253. struct    filed *Files;
  254. struct    filed consfile;
  255.  
  256. int    Debug;            /* debug flag */
  257. char    LocalHostName[MAXHOSTNAMELEN+1];    /* our hostname */
  258. char    *LocalDomain;        /* our local domain name */
  259. int    InetInuse = 0;        /* non-zero if INET sockets are being used */
  260. int    finet;            /* Internet datagram socket */
  261. int    LogPort;        /* port number for INET connections */
  262. int    Initialized = 0;    /* set when we have initialized ourselves */
  263. int    MarkInterval = 20 * 60;    /* interval between marks in seconds */
  264. int    MarkSeq = 0;        /* mark sequence number */
  265.  
  266. extern    int errno;
  267. extern    char *ctime(), *strchr(), *malloc();
  268. SIGHANDLER die(), domark(), init(), reapchild();
  269.  
  270. int
  271. main(argc, argv)
  272.     int argc;
  273.     char **argv;
  274. {
  275.     register int i;
  276.     register char *p;
  277.     int funix, inetm, fklog, klogm, len;
  278.     struct sockaddr_un sunx, fromunix;
  279.     struct sockaddr_in sin, frominet;
  280.     FILE *fp;
  281.     int ch;
  282.     char line[MSG_BSIZE + 1];
  283.     extern int optind;
  284.     extern char *optarg;
  285.  
  286.     while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
  287.         switch((char)ch) {
  288.         case 'd':        /* debug */
  289.             Debug++;
  290.             break;
  291.         case 'f':        /* configuration file */
  292.             ConfFile = optarg;
  293.             break;
  294.         case 'm':        /* mark interval */
  295.             MarkInterval = atoi(optarg) * 60;
  296.             break;
  297.         case 'p':        /* path */
  298.             LogName = optarg;
  299.             break;
  300.         case '?':
  301.         default:
  302.             usage();
  303.         }
  304.     if (argc -= optind)
  305.         usage();
  306.  
  307.     if (!Debug)
  308.         daemon(0, 0);
  309.     else
  310.         setlinebuf(stdout);
  311.  
  312.     consfile.f_type = F_CONSOLE;
  313.     (void) strcpy(consfile.f_un.f_fname, ctty);
  314.     (void) gethostname(LocalHostName, sizeof LocalHostName);
  315.     if (p = strchr(LocalHostName, '.')) {
  316.         *p++ = '\0';
  317.         LocalDomain = p;
  318.     }
  319.     else
  320.         LocalDomain = "";
  321.     (void) signal(SIGTERM, die);
  322.     if (Debug) {
  323.         (void) signal(SIGINT, die);
  324.         (void) signal(SIGQUIT, die);
  325.     }
  326.     else {
  327.         (void) signal(SIGINT, SIG_IGN);
  328.         (void) signal(SIGQUIT, SIG_IGN);
  329.     }
  330.     (void) signal(SIGCHLD, reapchild);
  331.     (void) signal(SIGALRM, domark);
  332.     (void) alarm(TIMERINTVL);
  333.     (void) unlink(LogName);
  334.  
  335.     bzero((char *)&sunx, sizeof(sunx));
  336.     sunx.sun_family = AF_UNIX;
  337.     (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path);
  338.     funix = socket(AF_UNIX, SOCK_DGRAM, 0);
  339.     if (funix < 0 || bind(funix, (struct sockaddr *) &sunx,
  340.         sizeof(sunx)) < 0 ||
  341.         chmod(LogName, 0666) < 0) {
  342.         (void) sprintf(line, "cannot create %s", LogName);
  343.         logerror(line);
  344.         dprintf("cannot create %s (%d)\n", LogName, errno);
  345.         die(0);
  346.     }
  347. #ifdef    DO_INET_SOCKET
  348.     finet = socket(AF_INET, SOCK_DGRAM, 0);
  349.     if (finet >= 0) {
  350.         struct servent *sp;
  351.  
  352.         sp = getservbyname("syslog", "udp");
  353.         if (sp == NULL) {
  354.             errno = 0;
  355.             logerror("syslog/udp: unknown service");
  356.             die(0);
  357.         }
  358.         bzero((char *)&sin, sizeof(sin)); /* added uunet!rbj */
  359.         sin.sin_family = AF_INET;
  360.         sin.sin_addr.s_addr = INADDR_ANY;
  361.         sin.sin_port = LogPort = htons(sp->s_port);
  362.         if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
  363.             logerror("bind");
  364.             if (!Debug)
  365.                 die(0);
  366.         } else {
  367.             inetm = FDMASK(finet);
  368.             InetInuse = 1;
  369.         }
  370.     }
  371. #else
  372.     finet = -1;
  373.     inetm = 0;
  374. #endif    /* DO_INET_SOCKET */
  375. #ifdef    _PATH_KLOG
  376.     if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0)
  377.         klogm = FDMASK(fklog);
  378.     else {
  379.         dprintf("can't open %s (%d)\n", _PATH_KLOG, errno);
  380.         klogm = 0;
  381.     }
  382. #else
  383.     fklog = -1;
  384.     klogm = 0;
  385. #endif    /* _PATH_KLOG */
  386.  
  387.     /* tuck my process id away */
  388.     fp = fopen(PidFile, "w");
  389.     if (fp != NULL) {
  390.         fprintf(fp, "%d\n", getpid());
  391.         (void) fclose(fp);
  392.     }
  393.  
  394.     dprintf("off & running....\n");
  395.  
  396.     init();
  397.     (void) signal(SIGHUP, init);
  398.  
  399.     for (;;) {
  400.         int nfds, readfds = FDMASK(funix) | inetm | klogm;
  401.  
  402.         errno = 0;
  403.         dprintf("readfds = %#x\n", readfds);
  404.         nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL,
  405.             (fd_set *) NULL, (struct timeval *) NULL);
  406.         if (nfds == 0)
  407.             continue;
  408.         if (nfds < 0) {
  409.             if (errno != EINTR)
  410.                 logerror("select");
  411.             continue;
  412.         }
  413.         dprintf("got a message (%d, %#x)\n", nfds, readfds);
  414.         if (readfds & klogm) {
  415.             i = read(fklog, line, sizeof(line) - 1);
  416.             if (i > 0) {
  417.                 line[i] = '\0';
  418.                 printsys(line);
  419.             } else if (i < 0 && errno != EINTR) {
  420.                 logerror("klog");
  421.                 fklog = -1;
  422.                 klogm = 0;
  423.             }
  424.         }
  425.         if (readfds & FDMASK(funix)) {
  426.             len = sizeof fromunix;
  427.             i = recvfrom(funix, line, MAXLINE, 0,
  428.                 (struct sockaddr *) &fromunix, &len);
  429.             if (i > 0) {
  430.                 line[i] = '\0';
  431.                 printline(LocalHostName, line);
  432.             } else if (i < 0 && errno != EINTR)
  433.                 logerror("recvfrom unix");
  434.         }
  435.         if (readfds & inetm) {
  436.             len = sizeof frominet;
  437.             i = recvfrom(finet, line, MAXLINE, 0,
  438.                 (struct sockaddr *) &frominet, &len);
  439.             if (i > 0) {
  440.                 extern char *cvthname();
  441.  
  442.                 line[i] = '\0';
  443.                 printline(cvthname(&frominet), line);
  444.             } else if (i < 0 && errno != EINTR)
  445.                 logerror("recvfrom inet");
  446.         }
  447.     }
  448. }
  449.  
  450. usage()
  451. {
  452.     (void) fprintf(stderr,
  453.         "usage: syslogd [-d] [-f conffile] [-m markinterval] [-p path]\n");
  454.     exit(1);
  455. }
  456.  
  457. /*
  458.  * Take a raw input line, decode the message, and print the message
  459.  * on the appropriate log files.
  460.  */
  461.  
  462. printline(hname, msg)
  463.     char *hname;
  464.     char *msg;
  465. {
  466.     register char *p, *q;
  467.     register int c;
  468.     char line[MAXLINE + 1];
  469.     int pri;
  470.  
  471.     /* test for special codes */
  472.     pri = DEFUPRI;
  473.     p = msg;
  474.     if (*p == '<') {
  475.         pri = 0;
  476.         while (isdigit(*++p))
  477.             pri = 10 * pri + (*p - '0');
  478.         if (*p == '>')
  479.             ++p;
  480.     }
  481.     if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  482.         pri = DEFUPRI;
  483.  
  484.     /* don't allow users to log kernel messages */
  485.     if (LOG_FAC(pri) == LOG_KERN)
  486.         pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri));
  487.  
  488.     q = line;
  489.  
  490.     while ((c = *p++ & 0177) != '\0' &&
  491.         q < &line[sizeof(line) - 1])
  492.         if (iscntrl(c))
  493.             if (c == '\n')
  494.                 *q++ = ' ';
  495.             else if (c == '\t')
  496.                 *q++ = '\t';
  497.             else {
  498.                 *q++ = '^';
  499.                 *q++ = c ^ 0100;
  500.             }
  501.         else
  502.             *q++ = c;
  503.     *q = '\0';
  504.  
  505.     logmsg(pri, line, hname, 0);
  506. }
  507.  
  508. /*
  509.  * Take a raw input line from /dev/klog, split and format similar to syslog().
  510.  */
  511.  
  512. printsys(msg)
  513.     char *msg;
  514. {
  515.     register char *p, *q;
  516.     register int c;
  517.     char line[MAXLINE + 1];
  518.     int pri, flags;
  519.     char *lp;
  520.  
  521.     (void) strcpy(line, "vmunix: ");
  522.     lp = line + strlen(line);
  523.     for (p = msg; *p != '\0'; ) {
  524.         flags = SYNC_FILE | ADDDATE;    /* fsync file after write */
  525.         pri = DEFSPRI;
  526.         if (*p == '<') {
  527.             pri = 0;
  528.             while (isdigit(*++p))
  529.                 pri = 10 * pri + (*p - '0');
  530.             if (*p == '>')
  531.                 ++p;
  532.         } else {
  533.             /* kernel printf's come out on console */
  534.             flags |= IGN_CONS;
  535.         }
  536.         if (pri &~ (LOG_FACMASK|LOG_PRIMASK))
  537.             pri = DEFSPRI;
  538.         q = lp;
  539.         while (*p != '\0' && (c = *p++) != '\n' &&
  540.             q < &line[MAXLINE])
  541.             *q++ = c;
  542.         *q = '\0';
  543.         logmsg(pri, line, LocalHostName, flags);
  544.     }
  545. }
  546.  
  547.  
  548. #ifdef    VERBOSE_DEBUG
  549. /*
  550.  *  Decode a numeric value to a symbolic name
  551.  */
  552. char *
  553. edoced(val, codetab)
  554.     int val;
  555.     CODE *codetab;
  556. {
  557.     register CODE *c;
  558.  
  559.     if (val >= 0)
  560.         for (c = codetab; c->c_val != -1; c++)
  561.             if (c->c_val == val)
  562.                 return (c->c_name);
  563.     return ("???");
  564. }
  565. #endif
  566.  
  567. time_t    now;
  568.  
  569. /*
  570.  * Log a message to the appropriate log files, users, etc. based on
  571.  * the priority.
  572.  */
  573.  
  574. logmsg(pri, msg, from, flags)
  575.     int pri;
  576.     char *msg, *from;
  577.     int flags;
  578. {
  579.     register struct filed *f;
  580.     int fac, prilev;
  581.     int omask, msglen;
  582.     char *timestamp;
  583.     time_t time();
  584.  
  585. #ifdef    VERBOSE_DEBUG
  586.     if (Debug) {
  587.         int pfac = (flags & MARK) ? INTERNAL_MARK : (pri & LOG_FACMASK);
  588.         printf("logmsg: {%s.%s} pri %o, flags %x, from %s, msg %s\n",
  589.             edoced(pfac, facilitynames),
  590.             edoced(LOG_PRI(pri), prioritynames),
  591.             pri, flags, from, msg);
  592.      }
  593. #else
  594.     dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n",
  595.         pri, flags, from, msg);
  596. #endif
  597.  
  598.     omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM));
  599.  
  600.     /*
  601.      * Check to see if msg looks non-standard.
  602.      */
  603.     msglen = strlen(msg);
  604.     if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' ||
  605.         msg[9] != ':' || msg[12] != ':' || msg[15] != ' ')
  606.         flags |= ADDDATE;
  607.  
  608.     (void) time(&now);
  609.     if (flags & ADDDATE)
  610.         timestamp = ctime(&now) + 4;
  611.     else {
  612.         timestamp = msg;
  613.         msg += 16;
  614.         msglen -= 16;
  615.     }
  616.  
  617.     /* extract facility and priority level */
  618.     if (flags & MARK)
  619.         fac = LOG_NFACILITIES;
  620.     else
  621.         fac = LOG_FAC(pri);
  622.     prilev = LOG_PRI(pri);
  623.  
  624.     /* log the message to the particular outputs */
  625.     if (!Initialized) {
  626.         f = &consfile;
  627.         f->f_file = open(ctty, O_WRONLY, 0);
  628.  
  629.         if (f->f_file >= 0) {
  630.             fprintlog(f, flags, msg);
  631.             (void) close(f->f_file);
  632.         }
  633.         (void) sigsetmask(omask);
  634.         return;
  635.     }
  636.     for (f = Files; f; f = f->f_nextone) {
  637.         /* skip messages that are incorrect priority */
  638.         if ((int)f->f_pmask[fac] < prilev ||
  639.             f->f_pmask[fac] == INTERNAL_NOPRI)
  640.             continue;
  641.  
  642.         if (f->f_type == F_CONSOLE && (flags & IGN_CONS))
  643.             continue;
  644.  
  645.         /* don't output marks to recently written files */
  646.         if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2)
  647.             continue;
  648.  
  649.         /*
  650.          * suppress duplicate lines to this file
  651.          */
  652.         if ((flags & MARK) == 0 && msglen == f->f_prevlen &&
  653.             !strcmp(msg, f->f_prevline) &&
  654.             !strcmp(from, f->f_prevhost)) {
  655.             (void) strncpy(f->f_lasttime, timestamp, 15);
  656.             f->f_prevcount++;
  657.             dprintf("msg repeated %d times, %ld sec of %d\n",
  658.                 f->f_prevcount, now - f->f_time,
  659.                 repeatinterval[f->f_repeatcount]);
  660.             /*
  661.              * If domark would have logged this by now,
  662.              * flush it now (so we don't hold isolated messages),
  663.              * but back off so we'll flush less often
  664.              * in the future.
  665.              */
  666.             if (now > REPEATTIME(f)) {
  667.                 fprintlog(f, flags, (char *)NULL);
  668.                 BACKOFF(f);
  669.             }
  670.         } else {
  671.             /* new line, save it */
  672.             if (f->f_prevcount)
  673.                 fprintlog(f, 0, (char *)NULL);
  674.             f->f_repeatcount = 0;
  675.             (void) strncpy(f->f_lasttime, timestamp, 15);
  676.             (void) strncpy(f->f_prevhost, from,
  677.                     sizeof(f->f_prevhost));
  678.             if (msglen < MAXSVLINE) {
  679.                 f->f_prevlen = msglen;
  680.                 f->f_prevpri = pri;
  681.                 (void) strcpy(f->f_prevline, msg);
  682.                 fprintlog(f, flags, (char *)NULL);
  683.             } else {
  684.                 f->f_prevline[0] = 0;
  685.                 f->f_prevlen = 0;
  686.                 fprintlog(f, flags, msg);
  687.             }
  688.         }
  689.     }
  690.     (void) sigsetmask(omask);
  691. }
  692.  
  693. fprintlog(f, flags, msg)
  694.     register struct filed *f;
  695.     int flags;
  696.     char *msg;
  697. {
  698.     struct iovec iov[6];
  699.     register struct iovec *v;
  700.     register int l;
  701.     char line[MAXLINE + 1], repbuf[80], greetings[200];
  702.  
  703.     v = iov;
  704.     if (f->f_type == F_WALL) {
  705.         v->iov_base = greetings;
  706.         sprintf(greetings,
  707.             "\r\n\7Message from syslogd@%s at %.24s ...\r\n",
  708.             f->f_prevhost, ctime(&now));
  709.         v->iov_len = strlen(greetings);
  710.         v++;
  711.         v->iov_base = "";
  712.         v->iov_len = 0;
  713.         v++;
  714.     } else {
  715.         v->iov_base = f->f_lasttime;
  716.         v->iov_len = 15;
  717.         v++;
  718.         v->iov_base = " ";
  719.         v->iov_len = 1;
  720.         v++;
  721.     }
  722.     v->iov_base = f->f_prevhost;
  723.     v->iov_len = strlen(v->iov_base);
  724.     v++;
  725.     v->iov_base = " ";
  726.     v->iov_len = 1;
  727.     v++;
  728.  
  729.     if (msg) {
  730.         v->iov_base = msg;
  731.         v->iov_len = strlen(msg);
  732.     } else if (f->f_prevcount > 1) {
  733.         v->iov_base = repbuf;
  734.         sprintf(repbuf, "last message repeated %d times",
  735.             f->f_prevcount);
  736.         v->iov_len = strlen(repbuf);
  737.     } else {
  738.         v->iov_base = f->f_prevline;
  739.         v->iov_len = f->f_prevlen;
  740.     }
  741.     v++;
  742.  
  743.     dprintf("Logging to %s", TypeNames[f->f_type]);
  744.     f->f_time = now;
  745.  
  746.     switch (f->f_type) {
  747.     case F_UNUSED:
  748.         dprintf("\n");
  749.         break;
  750.  
  751.     case F_FORW:
  752.         dprintf(" %s\n", f->f_un.f_forw.f_hname);
  753.         sprintf(line, "<%d>%.15s %s", f->f_prevpri,
  754.             iov[0].iov_base, iov[4].iov_base);
  755.         l = strlen(line);
  756.         if (l > MAXLINE)
  757.             l = MAXLINE;
  758.         if (sendto(finet, line, l, 0, &f->f_un.f_forw.f_addr,
  759.             sizeof f->f_un.f_forw.f_addr) != l) {
  760.             int e = errno;
  761.             (void) close(f->f_file);
  762.             f->f_type = F_UNUSED;
  763.             errno = e;
  764.             logerror("sendto");
  765.         }
  766.         break;
  767.  
  768.     case F_CONSOLE:
  769.         if (flags & IGN_CONS) {
  770.             dprintf(" (ignored)\n");
  771.             break;
  772.         }
  773.         /* FALLTHROUGH */
  774.  
  775.     case F_TTY:
  776.     case F_FILE:
  777.         dprintf(" %s\n", f->f_un.f_fname);
  778.         if (f->f_type != F_FILE) {
  779.             v->iov_base = "\r\n";
  780.             v->iov_len = 2;
  781.         } else {
  782.             v->iov_base = "\n";
  783.             v->iov_len = 1;
  784.         }
  785.     again:
  786.         if (writev(f->f_file, iov, 6) < 0) {
  787.             int e = errno;
  788.             (void) close(f->f_file);
  789.             /*
  790.              * Check for errors on TTY's due to loss of tty
  791.              */
  792.             if ((e == EIO || e == EBADF) && f->f_type != F_FILE) {
  793.                 f->f_file = open(f->f_un.f_fname,
  794.                     O_WRONLY|O_APPEND, 0);
  795.                 if (f->f_file < 0) {
  796.                     f->f_type = F_UNUSED;
  797.                     logerror(f->f_un.f_fname);
  798.                 } else
  799.                     goto again;
  800.             } else {
  801.                 f->f_type = F_UNUSED;
  802.                 errno = e;
  803.                 logerror(f->f_un.f_fname);
  804.             }
  805.         } else if (flags & SYNC_FILE)
  806.             (void) fsync(f->f_file);
  807.         break;
  808.  
  809.     case F_USERS:
  810.     case F_WALL:
  811.         dprintf("\n");
  812.         v->iov_base = "\r\n";
  813.         v->iov_len = 2;
  814.         wallmsg(f, iov);
  815.         break;
  816.     }
  817.     f->f_prevcount = 0;
  818. }
  819.  
  820. /*
  821.  *  WALLMSG -- Write a message to the world at large
  822.  *
  823.  *    Write the specified message to either the entire
  824.  *    world, or a list of approved users.
  825.  */
  826.  
  827. wallmsg(f, iov)
  828.     register struct filed *f;
  829.     struct iovec *iov;
  830. {
  831.     static int reenter;            /* avoid calling ourselves */
  832.     register FILE *uf;
  833.     register int i;
  834.     struct utmp ut;
  835.     char *p, *ttymsg();
  836.  
  837.     if (reenter++)
  838.         return;
  839.     if ((uf = fopen(_PATH_UTMP, "r")) == NULL) {
  840.         logerror(_PATH_UTMP);
  841.         reenter = 0;
  842.         return;
  843.     }
  844.     /* NOSTRICT */
  845.     while (fread((char *) &ut, sizeof ut, 1, uf) == 1) {
  846.         if (ut.ut_name[0] == '\0')
  847.             continue;
  848.         if (f->f_type == F_WALL) {
  849.             if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  850.                 errno = 0;    /* already in msg */
  851.                 logerror(p);
  852.             }
  853.             continue;
  854.         }
  855.         /* should we send the message to this user? */
  856.         for (i = 0; i < MAXUNAMES; i++) {
  857.             if (!f->f_un.f_uname[i][0])
  858.                 break;
  859.             if (!strncmp(f->f_un.f_uname[i], ut.ut_name,
  860.                 UT_NAMESIZE)) {
  861.                 if (p = ttymsg(iov, 6, ut.ut_line, 1)) {
  862.                     errno = 0;    /* already in msg */
  863.                     logerror(p);
  864.                 }
  865.                 break;
  866.             }
  867.         }
  868.     }
  869.     (void) fclose(uf);
  870.     reenter = 0;
  871. }
  872.  
  873. SIGHANDLER
  874. reapchild()
  875. {
  876.     WAITVALUE status;
  877.  
  878.     while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0)
  879.         continue;
  880. }
  881.  
  882. /*
  883.  * Return a printable representation of a host address.
  884.  */
  885. char *
  886. cvthname(f)
  887.     struct sockaddr_in *f;
  888. {
  889.     struct hostent *hp;
  890.     register char *p;
  891.     extern char *inet_ntoa();
  892.  
  893.     dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr));
  894.  
  895.     if (f->sin_family != AF_INET) {
  896.         dprintf("Malformed from address\n");
  897.         return ("???");
  898.     }
  899.     hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family);
  900.     if (hp == 0) {
  901.         dprintf("Host name for your address (%s) unknown\n",
  902.             inet_ntoa(f->sin_addr));
  903.         return (inet_ntoa(f->sin_addr));
  904.     }
  905.     if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
  906.         *p = '\0';
  907.     return (hp->h_name);
  908. }
  909.  
  910. SIGHANDLER
  911. domark()
  912. {
  913.     register struct filed *f;
  914.     time_t time();
  915.  
  916.     now = time((time_t *)NULL);
  917.     MarkSeq += TIMERINTVL;
  918.     if (MarkSeq >= MarkInterval) {
  919.         logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK);
  920.         MarkSeq = 0;
  921.     }
  922.  
  923.     for (f = Files; f; f = f->f_nextone) {
  924.         if (f->f_prevcount && now >= REPEATTIME(f)) {
  925.             dprintf("flush %s: repeated %d times, %d sec.\n",
  926.                 TypeNames[f->f_type], f->f_prevcount,
  927.                 repeatinterval[f->f_repeatcount]);
  928.             fprintlog(f, 0, (char *)NULL);
  929.             BACKOFF(f);
  930.         }
  931.     }
  932.     (void) alarm(TIMERINTVL);
  933. }
  934.  
  935. static char *
  936. xstrerror()
  937. {
  938.     extern int    sys_nerr;
  939.     extern char    *sys_errlist[];
  940.     extern int    errno;
  941.     static char    buff[30];
  942.  
  943.     if (errno >= 0 && errno < sys_nerr)
  944.     return sys_errlist[errno];
  945.     (void)sprintf(buff, "Error code %d\n", errno);
  946.     return buff;
  947. }
  948.  
  949. /*
  950.  * Print syslogd errors some place.
  951.  */
  952. logerror(type)
  953.     char *type;
  954. {
  955.     char buf[100];
  956.  
  957.     if (errno)
  958.         (void) sprintf(buf, "syslogd: %s: %s", type, xstrerror(errno));
  959.     else
  960.         (void) sprintf(buf, "syslogd: %s", type);
  961.     errno = 0;
  962.     dprintf("%s\n", buf);
  963.     logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
  964. }
  965.  
  966. SIGHANDLER
  967. die(sig)
  968. {
  969.     register struct filed *f;
  970.     char buf[100];
  971.  
  972.     for (f = Files; f != NULL; f = f->f_nextone) {
  973.         /* flush any pending output */
  974.         if (f->f_prevcount)
  975.             fprintlog(f, 0, (char *)NULL);
  976.     }
  977.     if (sig) {
  978.         dprintf("syslogd: exiting on signal %d\n", sig);
  979.         (void) sprintf(buf, "exiting on signal %d", sig);
  980.         errno = 0;
  981.         logerror(buf);
  982.     }
  983.     (void) unlink(LogName);
  984.     exit(0);
  985. }
  986.  
  987. /*
  988.  *  INIT -- Initialize syslogd from configuration table
  989.  */
  990.  
  991. SIGHANDLER
  992. init()
  993. {
  994.     register int i;
  995.     register FILE *cf;
  996.     register struct filed *f, *next, **nextp;
  997.     register char *p;
  998.     char cline[BUFSIZ];
  999.  
  1000.     dprintf("init\n");
  1001.  
  1002.     /*
  1003.      *  Close all open log files.
  1004.      */
  1005.     Initialized = 0;
  1006.     for (f = Files; f != NULL; f = next) {
  1007.         /* flush any pending output */
  1008.         if (f->f_prevcount)
  1009.             fprintlog(f, 0, (char *)NULL);
  1010.  
  1011.         switch (f->f_type) {
  1012.           case F_FILE:
  1013.           case F_TTY:
  1014.           case F_CONSOLE:
  1015.           case F_FORW:
  1016.             (void) close(f->f_file);
  1017.             break;
  1018.         }
  1019.         next = f->f_nextone;
  1020.         free((char *) f);
  1021.     }
  1022.     Files = NULL;
  1023.     nextp = &Files;
  1024.  
  1025.     /* open the configuration file */
  1026.     if ((cf = fopen(ConfFile, "r")) == NULL) {
  1027.         dprintf("cannot open %s\n", ConfFile);
  1028.         *nextp = (struct filed *)malloc(sizeof(*f));
  1029.         cfline("*.ERR\t/dev/console", *nextp);
  1030.         (*nextp)->f_nextone = (struct filed *)malloc(sizeof(*f));
  1031.         cfline("*.PANIC\t*", (*nextp)->f_nextone);
  1032.         Initialized = 1;
  1033.         return;
  1034.     }
  1035.  
  1036.     /*
  1037.      *  Foreach line in the conf table, open that file.
  1038.      */
  1039.     f = NULL;
  1040.     while (fgets(cline, sizeof cline, cf) != NULL) {
  1041.         /*
  1042.          * check for end-of-section, comments, strip off trailing
  1043.          * spaces and newline character.
  1044.          */
  1045.         for (p = cline; isspace(*p); ++p);
  1046.         if (*p == NULL || *p == '#')
  1047.             continue;
  1048.         for (p = strchr(cline, '\0'); isspace(*--p););
  1049.         *++p = '\0';
  1050.         f = (struct filed *)malloc(sizeof(*f));
  1051.         *nextp = f;
  1052.         nextp = &f->f_nextone;
  1053.         cfline(cline, f);
  1054.     }
  1055.  
  1056.     /* close the configuration file */
  1057.     (void) fclose(cf);
  1058.  
  1059.     Initialized = 1;
  1060.  
  1061.     if (Debug) {
  1062.         for (f = Files; f; f = f->f_nextone) {
  1063.             for (i = 0; i <= LOG_NFACILITIES; i++)
  1064.                 if (f->f_pmask[i] == INTERNAL_NOPRI)
  1065.                     printf("X ");
  1066.                 else
  1067.                     printf("%d ", f->f_pmask[i]);
  1068.             printf("%s: ", TypeNames[f->f_type]);
  1069.             switch (f->f_type) {
  1070.             case F_FILE:
  1071.             case F_TTY:
  1072.             case F_CONSOLE:
  1073.                 printf("%s", f->f_un.f_fname);
  1074.                 break;
  1075.  
  1076.             case F_FORW:
  1077.                 printf("%s", f->f_un.f_forw.f_hname);
  1078.                 break;
  1079.  
  1080.             case F_USERS:
  1081.                 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
  1082.                     printf("%s, ", f->f_un.f_uname[i]);
  1083.                 break;
  1084.             }
  1085.             printf("\n");
  1086.         }
  1087.     }
  1088.  
  1089.     logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE);
  1090.     dprintf("syslogd: restarted\n");
  1091. }
  1092.  
  1093. /*
  1094.  * Crack a configuration file line
  1095.  */
  1096.  
  1097. cfline(line, f)
  1098.     char *line;
  1099.     register struct filed *f;
  1100. {
  1101.     register char *p;
  1102.     register char *q;
  1103.     register int i;
  1104.     char *bp;
  1105.     int pri;
  1106.     struct hostent *hp;
  1107.     char buf[MAXLINE];
  1108.  
  1109.     dprintf("cfline(%s)\n", line);
  1110.  
  1111.     errno = 0;    /* keep strerror() stuff out of logerror messages */
  1112.  
  1113.     /* clear out file entry */
  1114.     bzero((char *) f, sizeof *f);
  1115.     for (i = 0; i <= LOG_NFACILITIES; i++)
  1116.         f->f_pmask[i] = INTERNAL_NOPRI;
  1117.  
  1118.     /* scan through the list of selectors */
  1119.     for (p = line; *p && *p != '\t';) {
  1120.  
  1121.         /* find the end of this facility name list */
  1122.         for (q = p; *q && *q != '\t' && *q++ != '.'; )
  1123.             continue;
  1124.  
  1125.         /* collect priority name */
  1126.         for (bp = buf; *q && !strchr("\t,;", *q); )
  1127.             *bp++ = *q++;
  1128.         *bp = '\0';
  1129.  
  1130.         /* skip cruft */
  1131.         while (strchr(", ;", *q))
  1132.             q++;
  1133.  
  1134.         /* decode priority name */
  1135.         pri = decode(buf, prioritynames);
  1136.         if (pri < 0) {
  1137.             char xbuf[200];
  1138.  
  1139.             (void) sprintf(xbuf, "unknown priority name \"%s\"",
  1140.                 buf);
  1141.             logerror(xbuf);
  1142.             return;
  1143.         }
  1144.  
  1145.         /* scan facilities */
  1146.         while (*p && !strchr("\t.;", *p)) {
  1147.             for (bp = buf; *p && !strchr("\t,;.", *p); )
  1148.                 *bp++ = *p++;
  1149.             *bp = '\0';
  1150.             if (*buf == '*')
  1151.                 for (i = 0; i < LOG_NFACILITIES; i++)
  1152.                     f->f_pmask[i] = pri;
  1153.             else {
  1154.                 i = decode(buf, facilitynames);
  1155.                 if (i < 0) {
  1156.                     char xbuf[200];
  1157.  
  1158.                     (void) sprintf(xbuf,
  1159.                         "unknown facility name \"%s\"",
  1160.                         buf);
  1161.                     logerror(xbuf);
  1162.                     return;
  1163.                 }
  1164.                 f->f_pmask[i >> 3] = pri;
  1165.             }
  1166.             while (*p == ',' || *p == ' ')
  1167.                 p++;
  1168.         }
  1169.  
  1170.         p = q;
  1171.     }
  1172.  
  1173.     /* skip to action part */
  1174.     while (*p == '\t')
  1175.         p++;
  1176.  
  1177.     switch (*p)
  1178.     {
  1179.     case '@':
  1180.         if (!InetInuse)
  1181.             break;
  1182.         (void) strcpy(f->f_un.f_forw.f_hname, ++p);
  1183.         hp = gethostbyname(p);
  1184.         if (hp == NULL) {
  1185.             logerror("hostname lookup error");
  1186.             break;
  1187.         }
  1188.         bzero((char *) &f->f_un.f_forw.f_addr,
  1189.              sizeof f->f_un.f_forw.f_addr);
  1190.         f->f_un.f_forw.f_addr.sin_family = AF_INET;
  1191.         f->f_un.f_forw.f_addr.sin_port = LogPort;
  1192.         bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length);
  1193.         f->f_type = F_FORW;
  1194.         break;
  1195.  
  1196.     case '/':
  1197.         (void) strcpy(f->f_un.f_fname, p);
  1198.         if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) {
  1199.             f->f_file = F_UNUSED;
  1200.             logerror(p);
  1201.             break;
  1202.         }
  1203.         if (isatty(f->f_file))
  1204.             f->f_type = F_TTY;
  1205.         else
  1206.             f->f_type = F_FILE;
  1207.         if (strcmp(p, ctty) == 0)
  1208.             f->f_type = F_CONSOLE;
  1209.         break;
  1210.  
  1211.     case '*':
  1212.         f->f_type = F_WALL;
  1213.         break;
  1214.  
  1215.     default:
  1216.         for (i = 0; i < MAXUNAMES && *p; i++) {
  1217.             for (q = p; *q && *q != ','; )
  1218.                 q++;
  1219.             (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE);
  1220.             if ((q - p) > UT_NAMESIZE)
  1221.                 f->f_un.f_uname[i][UT_NAMESIZE] = '\0';
  1222.             else
  1223.                 f->f_un.f_uname[i][q - p] = '\0';
  1224.             while (*q == ',' || *q == ' ')
  1225.                 q++;
  1226.             p = q;
  1227.         }
  1228.         f->f_type = F_USERS;
  1229.         break;
  1230.     }
  1231. }
  1232.  
  1233.  
  1234. /*
  1235.  *  Decode a symbolic name to a numeric value
  1236.  */
  1237.  
  1238. decode(name, codetab)
  1239.     char *name;
  1240.     CODE *codetab;
  1241. {
  1242.     register CODE *c;
  1243.     register char *p;
  1244.     char buf[40];
  1245.  
  1246.     if (isdigit(*name))
  1247.         return (atoi(name));
  1248.  
  1249.     (void) strcpy(buf, name);
  1250.     for (p = buf; *p; p++)
  1251.         if (isupper(*p))
  1252.             *p = tolower(*p);
  1253.     for (c = codetab; c->c_name; c++)
  1254.         if (!strcmp(buf, c->c_name))
  1255.             return (c->c_val);
  1256.  
  1257.     return (-1);
  1258. }
  1259.  
  1260. daemon(nochdir, noclose)
  1261.         int nochdir, noclose;
  1262. {
  1263.         int cpid;
  1264.  
  1265.         if ((cpid = fork()) == -1)
  1266.                 return (-1);
  1267.         if (cpid)
  1268.                 exit(0);
  1269.         (void) setsid();
  1270.         if (!nochdir)
  1271.                 (void) chdir("/");
  1272.         if (!noclose) {
  1273.                 int devnull = open("/dev/null", O_RDWR, 0);
  1274.  
  1275.                 if (devnull != -1) {
  1276.                         (void) dup2(devnull, 0);
  1277.                         (void) dup2(devnull, 1);
  1278.                         (void) dup2(devnull, 2);
  1279.                         if (devnull > 2)
  1280.                                 (void) close(devnull);
  1281.                 }
  1282.         }
  1283. }
  1284.  
  1285.  
  1286. /*
  1287.  * Display the contents of a uio structure on a terminal.  Used by wall(1)
  1288.  * and syslogd(8).  Forks and finishes in child if write would block, waiting
  1289.  * at most five minutes.  Returns pointer to error string on unexpected error;
  1290.  * string is not newline-terminated.  Various "normal" errors are ignored
  1291.  * (exclusive-use, lack of permission, etc.).
  1292.  */
  1293. char *
  1294. ttymsg(iov, iovcnt, line)
  1295.     struct iovec *iov;
  1296.     int iovcnt;
  1297.     char *line;
  1298. {
  1299.     static char device[64] = _PATH_DEV;
  1300.     static char errbuf[1024];
  1301.     register int cnt, fd, left, wret;
  1302.     struct iovec localiov[6];
  1303.     int forked = 0;
  1304.  
  1305.     if (iovcnt > 6)
  1306.         return ("too many iov's");
  1307.     /*
  1308.      * open will fail on slip lines or exclusive-use lines
  1309.      * if not running as root; not an error.
  1310.      */
  1311.     (void) strcpy(device + sizeof(_PATH_DEV) - 1, line);
  1312.     if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
  1313.         if (errno == EBUSY || errno == EACCES)
  1314.             return (NULL);
  1315.         (void) sprintf(errbuf, "%s: error %d", device, errno);
  1316.         return (errbuf);
  1317.     }
  1318.  
  1319.     for (cnt = left = 0; cnt < iovcnt; ++cnt)
  1320.         left += iov[cnt].iov_len;
  1321.  
  1322.     for (;;) {
  1323.         wret = writev(fd, iov, iovcnt);
  1324.         if (wret >= left)
  1325.             break;
  1326.         if (wret >= 0) {
  1327.             left -= wret;
  1328.             if (iov != localiov) {
  1329.                 bcopy(iov, localiov,
  1330.                     iovcnt * sizeof(struct iovec));
  1331.                 iov = localiov;
  1332.             }
  1333.             for (cnt = 0; wret >= iov->iov_len; ++cnt) {
  1334.                 wret -= iov->iov_len;
  1335.                 ++iov;
  1336.                 --iovcnt;
  1337.             }
  1338.             if (wret) {
  1339.                 iov->iov_base += wret;
  1340.                 iov->iov_len -= wret;
  1341.             }
  1342.             continue;
  1343.         }
  1344.         if (errno == EWOULDBLOCK) {
  1345.             int cpid, off = 0;
  1346.  
  1347.             if (forked) {
  1348.                 (void) close(fd);
  1349.                 _exit(1);
  1350.             }
  1351.             cpid = fork();
  1352.             if (cpid < 0) {
  1353.                 (void) sprintf(errbuf,
  1354.                     "fork: error %d", errno);
  1355.                 (void) close(fd);
  1356.                 return (errbuf);
  1357.             }
  1358.             if (cpid) {    /* parent */
  1359.                 (void) close(fd);
  1360.                 return (NULL);
  1361.             }
  1362.             forked++;
  1363.             /* wait at most 5 minutes */
  1364.             (void) signal(SIGALRM, SIG_DFL);
  1365.             (void) signal(SIGTERM, SIG_DFL); /* XXX */
  1366.             (void) sigsetmask(0);
  1367.             (void) alarm((u_int)(60 * 5));
  1368.             (void) fcntl(fd, FNDELAY, &off);
  1369.             continue;
  1370.         }
  1371.         /*
  1372.          * We get ENODEV on a slip line if we're running as root,
  1373.          * and EIO if the line just went away.
  1374.          */
  1375.         if (errno == ENODEV || errno == EIO)
  1376.             break;
  1377.         (void) close(fd);
  1378.         if (forked)
  1379.             _exit(1);
  1380.         (void) sprintf(errbuf, "%s: error %d", errno);
  1381.         return (errbuf);
  1382.     }
  1383.  
  1384.     (void) close(fd);
  1385.     if (forked)
  1386.         _exit(0);
  1387.     return (NULL);
  1388. }
  1389.